// 根据授权码从模拟api获取token,刷新token以及告知第三方解绑
import { AbstractPlatform } from '../AbstractPlatform';
import {getBrandConfig} from "../getBrandConfig";
import {MockThirdParty} from "../../mock/MockThirdParty";
import {AppDataSource} from "../../config/database";
import {BranchAccount} from "../../entity/BranchAccount";


export class MideaMock extends AbstractPlatform {
    private mockThirdParty: MockThirdParty;
    private config = getBrandConfig("midea");

    constructor() {
        super();
        const config = getBrandConfig('midea');
        this.mockThirdParty = new MockThirdParty(config.app_id, config.app_secret);
    }

    async exchangeToken(code: string): Promise<{ access_token: string; expires_in: number }> {
        this.logExchange('midea', true);
        try {
            const response = await this.mockThirdParty.exchangeToken(code);

            return {
                access_token: response.access_token,
                expires_in: response.expires_in
            };
        } catch (e: any) {
            throw new Error(`Failed to exchange token: ${e.message}`);
        }
    }

    async revokeToken(token: string): Promise<void> {
        try {
            await this.mockThirdParty.revokeToken(token);
        } catch (error: any) {
            throw new Error(`Failed to revoke token: ${error.message}`);
        }
    }


    async refreshToken(userId: string, oldToken: string): Promise<{ access_token: string; expires_in: number }> {
        try {
            const response = await this.mockThirdParty.refreshToken(userId, oldToken);

            return {
                access_token: response.access_token,
                expires_in: response.expires_in,
            };
        } catch (error: any) {
            throw new Error(`Failed to refresh token: ${error.message}`);
        }
    }


    async getDeviceList(accessToken: string): Promise<{
        did: string;
        name: string;
        type: string;
        online: boolean;
    }[]> {
        const url = 'http://localhost:3000/midea/devices';
        const clientId = this.config.app_id;

        // 生成唯一的 reqId（使用时间戳）
        const reqId = Date.now().toString();

        // 创建带参数的 URL
        const urlWithParams = new URL(url);
        urlWithParams.searchParams.append('reqId', reqId.toString());

        const res = await fetch(url, {
            method: 'GET',
            headers: {
                Authorization: `Bearer ${accessToken}`,
                ClientId: clientId
            }
        });

        const json = await res.json();

        if (res.status !== 200 || json.code !== 200) {
            throw new Error(`获取美的设备列表失败: ${json.message || res.status}`);
        }

        const applianceList = json.data.applianceList || [];

        return applianceList.map((item: any) => ({
            did: item.virtualId,
            name: item.name,
            type: item.type,
            online: item.online
        }));

    }


    async subscribeDevice(accessToken: string, deviceId: string): Promise<void> {
        const reqId = Date.now().toString();
        const url = 'http://localhost:3000/midea/device/subscribe';

        const res = await fetch(url, {
            method: 'POST',
            headers: {
                Authorization: accessToken,
                ClientId: this.config.app_id,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                reqId,
                applianceCode: deviceId
            })
        });

        const json = await res.json();

        if (res.status !== 200) {
            throw new Error(`Midea订阅失败：HTTP状态码 ${res.status}`);
        }

        if (json.code === 1300) {
            throw new Error(`Midea订阅失败：设备不存在`);
        }

        if (json.code === 1006) {
            throw new Error(`Midea订阅失败：用户验证失败`);
        }

        console.log(`[SUBSCRIBE] Midea 设备 ${deviceId} 订阅成功 (reqId: ${reqId})`);
    }


    async revokeDeviceSubscription(userId: string, deviceId: string): Promise<void> {
        const reqId = Date.now().toString();
        const tokenRepo = AppDataSource.getRepository(BranchAccount);
        const record = await tokenRepo.findOne({where: {userId, brand: 'midea'}});

        if (!record) throw new Error(`未找到美的授权信息`);

        const res = await fetch('http://localhost:3000/midea/device/subscribe/cancel', {
            method: 'POST',
            headers: {
                Authorization: record.token,
                ClientId: this.config.app_id,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                reqId,
                applianceCode: deviceId
            })
        });

        const json = await res.json();

        if (res.status !== 200) {
            throw new Error(`Midea取消订阅失败: ${res.status}`);
        }

        if (json.code === 1300) {
            throw new Error(`设备不存在`);
        } else if (json.code === 1006) {
            throw new Error(`用户验证失败`);
        }

        console.log(`[UNSUB] Midea 设备 ${deviceId} 取消订阅成功`);
    }


    // 控制api调用
    async controlDevice(
        did: string,
        operation: string,
        value: any,
        accessToken: string
    ): Promise<{ status: { result: 1 | 0; isSameState: 0 | 1 } }> {
        const reqId = Date.now().toString();

        try {
            const res = await fetch('http://localhost:3000/midea/device/control', {
                method: 'POST',
                headers: {
                    Authorization: accessToken,
                    ClientId: this.config.app_id, // 假设 this.config.app_id 是客户端ID
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    reqId,
                    applianceId: did, // 美的设备ID
                    control: {
                        operation,
                        value,
                    },
                }),
            });

            // 即使是错误响应，也尝试解析 JSON，以便获取 code 和 message
            const json = await res.json();

            // 优先检查 HTTP 状态码，因为非200的响应可能不包含完整的json.code
            if (res.status !== 200) {
                let errorMessage: string = json.message || `HTTP错误: ${res.status}`;
                const errCode = json.code ?? res.status; // 如果有json.code就用，否则用HTTP状态码

                // 根据后端定义的错误码提供更具体的兼容信息
                switch (json.code) {
                    case 1006:
                        errorMessage = '用户验证失败';
                        break;
                    case 1300:
                        errorMessage = '设备不存在';
                        break;
                    case 1002:
                        errorMessage = '参数非法';
                        break;
                    // 其他未明确的错误码或通用HTTP错误，保留原始消息
                }
                // 抛出带有具体信息的错误，以便外部捕获
                throw new Error(errorMessage + ` (code: ${errCode})`);
            }

            // 此时 res.status 是 200，检查 json.code
            if (json.code !== 200) {
                let errorMessage: string;
                switch (json.code) {
                    case 1006:
                        errorMessage = '用户验证失败';
                        break;
                    case 1300:
                        errorMessage = '设备不存在';
                        break;
                    case 1002:
                        errorMessage = '参数非法';
                        break;
                    default:
                        errorMessage = json.message || '美的控制API返回非200 code';
                        break;
                }
                // 抛出带有具体信息的错误，包括原始code
                throw new Error(errorMessage + ` (code: ${json.code})`);
            }

            // 根据后端提供的返回示例，json.status.result 才是实际操作结果
            // 如果 status.result 不是 1，但 isSameState 是 1，则视为成功（状态已达成）
            if (json.status?.result !== 1 && json.isSameState === 1) {
                console.log(`[MideaControl] 设备 ${did} 状态已是 ${operation} = ${value}，无需改变。`);
                return {
                    status: {
                        result: 1, // 视为成功
                        isSameState: 1 // 表示状态相同
                    }
                };
            } else if (json.status?.result !== 1) {
                // 如果 result 不是 1 且 isSameState 也不是 1，则操作未成功
                throw new Error(`设备 ${did} 操作 ${operation} 未成功 (result: ${json.status?.result})`);
            }

            console.log(`[MideaControl] 成功控制 ${did}：${operation} = ${value}`);

            // 成功时返回与原始要求一致的格式
            return {
                status: {
                    result: 1, // 成功则 result 为 1
                    isSameState: json.isSameState ?? 0 // 如果不存在，默认为0
                }
            };

        } catch (error: any) {
            console.error(`[MideaControl Error] 控制设备 ${did} 失败:`, error.message);
            // 继续抛出错误，确保外部能捕获到并处理
            throw error;
        }
    }
}
